package cn.juque.redoctopus.client.appender;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.classic.spi.StackTraceElementProxy;
import ch.qos.logback.core.UnsynchronizedAppenderBase;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.juque.common.disruptor.DisruptorHandler;
import cn.juque.redoctopus.client.bo.LogEventBO;
import cn.juque.redoctopus.client.config.OctopusListener;
import cn.juque.redoctopus.client.disruptor.event.LogEventServiceImpl;
import cn.juque.redoctopus.client.util.IpUtil;
import cn.juque.redoctopus.client.util.OctopusContextUtil;
import java.util.Arrays;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * @author nuoka
 * @version 1.0.0
 * <li>IntelliJ IDEA</li>
 * <li>cn.juque.redoctopus.client.appender</li>
 * @date 2020/9/12 23:29
 **/
@Slf4j
@Data
public class OctLogbackAppender extends UnsynchronizedAppenderBase<ILoggingEvent> {

    /**
     * 服务编号
     */
    private String serviceNo;

    /**
     * 服务名称
     */
    private String serviceName;

    /**
     * 日志级别
     */
    private String level = "ERROR";

    /**
     * 输出日志的类的前缀
     */
    private String prefix;

    @Override
    protected void append(ILoggingEvent eventObject) {

        if (!Boolean.TRUE.equals(OctopusListener.startSuccess)) {
            return;
        }

        Level targetLevel = eventObject.getLevel();
        if (null == targetLevel) {
            targetLevel = Level.ERROR;
        }
        Level sourceLevel = Level.toLevel(this.level);
        if (targetLevel.levelInt < sourceLevel.levelInt) {
            return ;
        }

        String loggerName = eventObject.getLoggerName();
        if (CharSequenceUtil.isNotEmpty(this.prefix) && !CharSequenceUtil.startWith(loggerName, this.prefix)) {
            return;
        }
        LogEventBO logEventBO = new LogEventBO();
        logEventBO.setBusinessEventService(LogEventServiceImpl.BEAN_NAME);
        logEventBO.setServiceNo(this.serviceNo);
        logEventBO.setServiceName(this.serviceName);
        logEventBO.setThreadId(Thread.currentThread().getId());
        logEventBO.setLevel(targetLevel.levelStr);
        logEventBO.setIp(IpUtil.ip4Address());
        logEventBO.setTimestamp(eventObject.getTimeStamp());
        logEventBO.setMessage(eventObject.getFormattedMessage());

        IThrowableProxy throwable = eventObject.getThrowableProxy();
        if (null != throwable) {
            logEventBO.setMessage(logEventBO.getMessage() + ": " + throwable.getMessage());
            logEventBO.setThrowable(this.getStackTrace(throwable.getStackTraceElementProxyArray()));
        }

        // 添加到队列
        DisruptorHandler disruptorHandler = OctopusContextUtil.getBean(DisruptorHandler.class);
        disruptorHandler.publish(logEventBO);
    }

    /**
     * 获取堆栈信息
     * @param stackArray 堆栈信息
     * @return String
     */
    private String getStackTrace(StackTraceElementProxy[] stackArray) {
        if (ArrayUtil.isEmpty(stackArray)) {
            return "";
        }
        StringBuilder stringBuilder = new StringBuilder();
        Arrays.stream(stackArray).forEach(t -> stringBuilder.append(t.getSTEAsString()));

        return stringBuilder.toString();
    }
}
